package com.elite.ffmpegshell;

import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Encoder {
    private static final Log log = LogFactory.getLog(Encoder.class);
    private static final Pattern FORMAT_PATTERN = Pattern.compile("^\\s*([D ])([E ])\\s+([\\w,]+)\\s+.+$");
    private FFMPEGLocator locator;

    public Encoder() {
        this.locator = new FFMPEGLocator();
    }

    public Encoder(FFMPEGLocator locator) {
        this.locator = locator;
    }

    public void getInfo(File source) throws Exception {
        FFMPEGExecutor ffmpeg = this.locator.createExecutor();
        ffmpeg.addArgument("-i");
        ffmpeg.addArgument(source.getAbsolutePath());

        try {
            ffmpeg.execute();
            StreamGobbler errorGobbler = new StreamGobbler(ffmpeg.getErrorStream(), "ERROR");
            errorGobbler.start();
            StreamGobbler outGobbler = new StreamGobbler(ffmpeg.getInputStream(), "STDOUT");
            outGobbler.start();
        } catch (IOException var9) {
            var9.printStackTrace();
        }

        try {
            System.out.println(ffmpeg.waitFor());
        } finally {
            ffmpeg.destroy();
        }

    }

    public List<String> getSupportedEncodingFormats() throws InterruptedException, IOException {
        List<String> res = new ArrayList();
        FFMPEGExecutor ffmpeg = this.locator.createExecutor();
        ffmpeg.addArgument("-formats");
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            ffmpeg.execute();
            StreamGobbler errorGobbler = new StreamGobbler(ffmpeg.getErrorStream(), "ERROR");
            errorGobbler.start();
            StreamGobbler outGobbler = new StreamGobbler(ffmpeg.getInputStream(), "STDOUT", baos);
            outGobbler.start();
        } catch (IOException var16) {
            var16.printStackTrace();
        }

        try {
            ffmpeg.waitFor();
            byte[] bytes = baos.toByteArray();
            BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes)));
            int lineCount = 0;

            String line;
            while((line = reader.readLine()) != null) {
                if (line.trim().length() != 0) {
                    if (lineCount > 3) {
                        Matcher matcher = FORMAT_PATTERN.matcher(line);
                        if (!matcher.matches()) {
                            break;
                        }

                        String encoderFlag = matcher.group(2);
                        if ("E".equals(encoderFlag)) {
                            String aux = matcher.group(3);
                            StringTokenizer st = new StringTokenizer(aux, ",");

                            while(st.hasMoreTokens()) {
                                String token = st.nextToken().trim();
                                if (!res.contains(token)) {
                                    res.add(token);
                                }
                            }
                        }
                    }

                    ++lineCount;
                }
            }
        } finally {
            ffmpeg.destroy();
        }

        return res;
    }

    public List<String> getSupportedDecodingFormats() throws InterruptedException, IOException {
        List<String> res = new ArrayList();
        FFMPEGExecutor ffmpeg = this.locator.createExecutor();
        ffmpeg.addArgument("-formats");
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try {
            ffmpeg.execute();
            StreamGobbler errorGobbler = new StreamGobbler(ffmpeg.getErrorStream(), "ERROR");
            errorGobbler.start();
            StreamGobbler outGobbler = new StreamGobbler(ffmpeg.getInputStream(), "STDOUT", baos);
            outGobbler.start();
        } catch (IOException var16) {
            var16.printStackTrace();
        }

        try {
            ffmpeg.waitFor();
            byte[] bytes = baos.toByteArray();
            BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes)));
            int lineCount = 0;

            String line;
            while((line = reader.readLine()) != null) {
                if (line.trim().length() != 0) {
                    if (lineCount > 3) {
                        Matcher matcher = FORMAT_PATTERN.matcher(line);
                        if (!matcher.matches()) {
                            break;
                        }

                        String encoderFlag = matcher.group(1);
                        if ("D".equals(encoderFlag)) {
                            String aux = matcher.group(3);
                            StringTokenizer st = new StringTokenizer(aux, ",");

                            while(st.hasMoreTokens()) {
                                String token = st.nextToken().trim();
                                if (!res.contains(token)) {
                                    res.add(token);
                                }
                            }
                        }
                    }

                    ++lineCount;
                }
            }
        } finally {
            ffmpeg.destroy();
        }

        return res;
    }

    public int convert(File source, File target) throws InterruptedException, IOException {
        FFMPEGExecutor ffmpeg = this.locator.createExecutor();
        ffmpeg.addArgument("-i");
        ffmpeg.addArgument(source.getAbsolutePath());
        ffmpeg.addArgument(target.getAbsolutePath());
        ffmpeg.addArgument("-y");

        try {
            ffmpeg.execute();
            StreamGobbler errorGobbler = new StreamGobbler(ffmpeg.getErrorStream(), "ERROR");
            errorGobbler.start();
            StreamGobbler outGobbler = new StreamGobbler(ffmpeg.getInputStream(), "STDOUT");
            outGobbler.start();
        } catch (IOException var11) {
            var11.printStackTrace();
        }

        int ret;
        try {
            ret = ffmpeg.waitFor();
        } finally {
            ffmpeg.destroy();
        }

        return ret;
    }

    public byte[] convertAmrToMp3(byte[] data) throws IOException, InterruptedException, EncoderException {
        File temp = this.locator.getTempFolder();
        String rid = UUID.randomUUID().toString();
        File amrFile = new File(temp, rid + ".oga");
        File mp3File = new File(temp, rid + ".mp3");
        FileUtils.writeByteArrayToFile(amrFile, data);
        int r = this.convert(amrFile, mp3File);
        if (r == 0) {
            byte[] bytes = FileUtils.readFileToByteArray(mp3File);
            FileUtils.deleteQuietly(mp3File);
            log.debug("Encoder convertAmrToMp3 Succ!");
            return bytes;
        } else {
            FileUtils.deleteQuietly(amrFile);
            // throw new EncoderException("Cann't convert with ffmpeg.");
            log.warn("Encoder convertAmrToMp3 Cann't convert with ffmpeg.!");
            return data;
        }
    }
}
